package com.seleniti.enpareja.android.ui.view;

import org.ioc.commons.flowcontrol.actioncontroller.IsExternalAction;
import org.ioc.commons.flowcontrol.eventbus.IsEvent;
import org.ioc.commons.flowcontrol.logincontroller.IsLoggedUserInfoConsumer;
import org.ioc.commons.flowcontrol.logincontroller.LoginController;
import org.ioc.commons.flowcontrol.operationmanager.IsOperation;
import org.ioc.commons.flowcontrol.placecontroller.HasPlaceData;
import org.ioc.commons.flowcontrol.placecontroller.PlaceController;
import org.ioc.commons.impl.android.ui.SupportFragmentView;
import org.ioc.commons.model.globaldata.GlobalDataController;
import org.ioc.commons.ui.HasValue;
import org.ioc.commons.ui.IsViewPresenter;
import org.ioc.commons.ui.impl.BaseAdapter;
import org.ioc.commons.ui.impl.HasValueAdapter;
import org.ioc.commons.utils.Format;
import org.ioc.commons.utils.FormatterLogger;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.ShareActionProvider;
import android.text.Html;
import android.text.Spanned;
import android.view.View;
import android.widget.ListView;

import com.seleniti.enpareja.android.control.entrypoint.EnParejaAndroid;
import com.seleniti.enpareja.controller.common.GlobalData;
import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.controller.control.controller.LoginFailedCause;
import com.seleniti.enpareja.controller.control.controller.LoginParams;
import com.seleniti.enpareja.controller.control.factory.ClientFactory;
import com.seleniti.enpareja.controller.control.place.EnParejaPlace;
import com.seleniti.enpareja.controller.model.integration.database.domain.Couple;
import com.seleniti.enpareja.controller.model.integration.service.SecurityManagementService;
import com.seleniti.enpareja.controller.ui.view.EnParejaView;

public abstract class EnParejaBaseView<E extends Enum<? extends IsEvent>, O extends Enum<? extends IsOperation>, A extends Enum<? extends IsExternalAction>, P extends IsViewPresenter>
		extends SupportFragmentView<E, O, A, P> implements IsLoggedUserInfoConsumer<LoggedUserInfo>,
		EnParejaView<E, O, A> {

	private static final FormatterLogger logger = FormatterLogger.getLogger(EnParejaBaseView.class);

	private static boolean updatedLastAccess;

	private ClientFactory clientFactory;

	private final boolean requiresBeLoggedIn;
	private GlobalDataController<GlobalData> globalDataController;
	private PlaceController placeController;
	private SecurityManagementService securityService;

	private LoginController<LoggedUserInfo, LoginFailedCause, LoginParams, String> loginController;

	private int savedScrollPositionIndex;
	private int savedScrollPositionTop;

	protected ShareActionProvider mShareActionProvider;

	public EnParejaBaseView(boolean requiresBeLoggedIn) {
		this(requiresBeLoggedIn, true);
	}

	public EnParejaBaseView(boolean requiresBeLoggedIn, boolean autoActivation) {
		super(autoActivation);
		this.requiresBeLoggedIn = requiresBeLoggedIn;
	}

	public boolean isRequiresBeLoggedIn() {
		return requiresBeLoggedIn;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		this.clientFactory = ((EnParejaAndroid) this.getActivity().getApplication()).getClientFactory();
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);

		this.globalDataController = clientFactory.getGlobalDataController();
		this.placeController = clientFactory.getPlaceController().forThisObject(this);

		this.loginController = clientFactory.getLoginController();
		this.securityService = clientFactory.getServiceManager().serviceFactory().securityManagementService();
	}

	@Override
	public void onStart() {
		// boolean initiallized = this.isInitialized();
		super.onStart();

		if (this.requiresBeLoggedIn) {

			/**
			 * It will continue to #onLoggedUserInfoDataReady() method
			 */
			this.loginController.requiresLoggedUserInfoIfActive(this);
		}
	}

	@Override
	public void onDestroyView() {
		super.onDestroyView();

		/**
		 * Clean all old adapters
		 */
		BaseAdapter.cleanAdapters(this);
	}

	@Override
	public void onLoggedUserInfoNotReadyYet() {
		/*
		 * Nothing to do
		 */
	}

	@Override
	public void onLoggedUserInfoDataUpdated(LoggedUserInfo loggedUserInfo) {
		// Nothing to do
	}

	@Override
	public void onLoggedUserInfoDataReady() {
		logger.entering("onRequiredGlobalDataReady");

		LoggedUserInfo loggedUserInfo = this.loginController.getLoggedUserInfo();

		logger.info("Logged user info {0}", loggedUserInfo);

		if (loggedUserInfo == null || !loggedUserInfo.isLogged()) {
			HasPlaceData currentPlaceData = this.placeController.getCurrentPlaceData();
			EnParejaPlace goWhenLoginOk = (EnParejaPlace) (currentPlaceData != null ? currentPlaceData.getPlaceId()
					: null);

			logger.info("Not logged in");

			logger.info("Going to login place");
			this.placeController.goTo(true, EnParejaPlace.LoginPlace, false, null, goWhenLoginOk);
			return;
		} else {
			logger.info("Logged in: {0}", loggedUserInfo);
			if (this.getActivity() != null && !EnParejaBaseView.updatedLastAccess) {
				logger.info("Updating last access date");
				EnParejaBaseView.updatedLastAccess = true;
				this.securityService.updateLastAccess(loggedUserInfo.getUserId()).caller(this);
			}
		}

		logger.exiting("onRequiredGlobalDataReady");
	}

	protected void saveScrollPosition(ListView mList) {
		// save index and top position
		this.savedScrollPositionIndex = mList.getFirstVisiblePosition();
		View v = mList.getChildAt(0);
		this.savedScrollPositionTop = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());
	}

	protected void restoreScrollPosition(ListView mList) {
		mList.setSelectionFromTop(savedScrollPositionIndex, savedScrollPositionTop);
	}

	// Call to update the share intent
	@SafeVarargs
	final protected <T> void setShareIntent(SetShareIntentParameter<T>... parameters) {
		if (mShareActionProvider != null) {
			Intent sendIntent = new Intent();
			sendIntent.setAction(Intent.ACTION_SEND);
			StringBuffer sb = new StringBuffer();
			for (SetShareIntentParameter<T> parameter : parameters) {
				String text = Format.collectionToString(parameter.getHeader() + ":\n- ", "\n- ", "",
						parameter.getList(), parameter.getFormatter());
				sb.append(text).append('\n');
			}
			sendIntent.putExtra(Intent.EXTRA_TEXT, sb.toString());
			sendIntent.setType("text/plain");

			mShareActionProvider.setShareIntent(sendIntent);
		}
	}

	@SafeVarargs
	protected final <N extends Enum<?>> boolean requiresRepaint(N v1, N v2, N... values) {
		boolean requiresRepaint = false;

		for (N value : values) {
			requiresRepaint |= (v1 == value && v2 != value) || (v1 != value && v2 == value);
		}

		return requiresRepaint;
	}

	@Override
	public HasValue<Couple> couple() {
		return HasValueAdapter.<Couple> forField("couple", this);
	}

	protected Spanned maskEmail(String email) {
		if (email != null) {
			String parts[] = email.split("@");
			String username = parts[0];
			String server = parts[1];

			boolean isMask = false;
			if (username.length() > 2) {
				StringBuffer sb = new StringBuffer();
				for (int i = 0; i < username.length(); i++) {
					if (i == 0 || i == username.length() - 1) {
						if (isMask) {
							sb.append("</i>");
						}
						sb.append(username.charAt(i));
					} else {
						if (!isMask) {
							sb.append(Format.substitute("<i style='{0}'>", "font-style: italic; color: #93B5D5;"));
							isMask = true;
						}
						sb.append('x');
					}
				}
				username = sb.toString();
			}

			return Html.fromHtml(Format.substitute("{0}@{1}", username, server));

		} else {
			return null;
		}
	}
}
